{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Prompt"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "千帆提供了 Prompt 管理功能，可以快速地使用平台预置的优质 Prompt，或者保存用户自定义的 Prompt。SDK 也为用户快速使用 Prompt 提供了辅助。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Prompt 相关功能需要使用 Access Key 和 Secret Key 进行鉴权，获取方式参见 [文档](https://cloud.baidu.com/doc/Reference/s/9jwvz2egb)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import qianfan\n",
    "\n",
    "os.environ[\"QIANFAN_ACCESS_KEY\"] = \"your access key\"\n",
    "os.environ[\"QIANFAN_SECRET_KEY\"] = \"your secret key\""
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以通过这一方式导入 Prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qianfan.common import Prompt"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 快速使用"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "平台上预置的 Prompt 以及用户自定义的模型都可以在 [千帆控制台](https://console.bce.baidu.com/qianfan/prompt/template) 获得，之后可以在 SDK 中用 Prompt 的名称快速获取 Prompt 对象。\n",
    "\n",
    "加载平台上的相关资源需要使用 hub 功能。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qianfan.common.hub import hub\n",
    "\n",
    "p = hub.load(\"prompt/区域美食推荐\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "之后就可以调用 `render` 方法对 Prompt 模版进行填充，得到最终的文本。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "作为游客，告诉我上海必吃的10大美食\n"
     ]
    }
   ],
   "source": [
    "# 第二个参数是 negative prompt，文生文场景下为空，所以用 _ 省略\n",
    "prompt, _ = p.render(region=\"上海\")\n",
    "print(prompt)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "也可以通过如下方式获得 Prompt 的一些元信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "作为游客，告诉我{region}必吃的10大美食\n",
      "['region']\n"
     ]
    }
   ],
   "source": [
    "print(p.template)\n",
    "print(p.variables)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "SDK 也支持文生图类型的 Prompt，可以通过文生图类的 Prompt 名称进行初始化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "white hair female, close up character design, multiple concept designs, concept design sheet, white background, style of Yoshitaka Amano\n",
      "(worst quality, low quality:1.4), deformed iris, deformed pupils, (deformeddistorted, disfigured:1.3), cropped, out of frame.poorly drawn, bad anatomy, wrong anatomy, extralimb, missing limb, floating limbs\n"
     ]
    }
   ],
   "source": [
    "txt2img_prompt = hub.load(\"prompt/角色设计\")\n",
    "\n",
    "prompt, negative_prompt = txt2img_prompt.render()\n",
    "print(prompt)\n",
    "print(negative_prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Prompt 的场景可以通过 `scene_type` 属性获得"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from qianfan.consts import PromptSceneType\n",
    "\n",
    "txt2img_prompt.scene_type == PromptSceneType.Text2Image"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "借助 Prompt，我们就可以快速地完成一些任务，比如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "作为游客，上海必吃的十大美食包括：\n",
      "\n",
      "1. **生煎馒头**：上海特色早餐，鲜肉馅，底部脆硬，整体味道鲜美。\n",
      "2. **小笼包**：上海的小笼包以汤汁丰足、味道醇正著称。\n",
      "3. **蟹壳黄**：上海本地特色小吃，以烤至酥脆的饼皮和咸蛋黄肉馅为主。\n",
      "4. **白斩鸡**：最原汁原味的上海白斩鸡搭配甜酱是最佳的选择。\n",
      "5. **糖醋排骨**：使用传统的糖醋工艺制作的上海特色菜肴，酸甜可口。\n",
      "6. **炸猪排**：与排骨相似的上海特色小吃，通常与番茄酱一起食用。\n",
      "7. **清炒虾仁**：上海的传统名菜，口感鲜美，营养丰富。\n",
      "8. **响油鳝糊**：上海本地的特色鳝鱼美食，味道鲜美，做法相对复杂。\n",
      "9. **三鲜馄饨**：上海的传统小吃，以鲜肉、虾仁和海鲜为主要馅料，味道鲜美。\n",
      "10. **糟卤**：一种特殊的调味料，可以增加食物的鲜美程度，尤其适合海鲜类食品。\n",
      "\n",
      "以上十种美食涵盖了甜、咸、酥、脆、鲜等多种口感，可以满足不同游客的口味。在品尝美食的同时，也可以搭配上海本地的茶点，体验上海的饮食文化。\n"
     ]
    }
   ],
   "source": [
    "import qianfan\n",
    "\n",
    "p = hub.load(\"prompt/区域美食推荐\")\n",
    "\n",
    "def recommend_food(region):\n",
    "    prompt, _ = p.render(region=region)\n",
    "    r = qianfan.Completion().do(prompt)\n",
    "    return r['result']\n",
    "\n",
    "print(recommend_food(\"上海\"))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 本地 Prompt"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果不希望使用平台上的模型，只希望本地尝试，也可以通过 Prompt 对象实现，初始化时仅传入 `template` 字段即可。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "本地 prompt hello\n"
     ]
    }
   ],
   "source": [
    "p = Prompt(\"本地 prompt {var1}\")\n",
    "\n",
    "prompt, _ = p.render(var1=\"hello\")\n",
    "print(prompt)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "还可以传入更多参数，创建一个更为复杂的本地 Prompt，比如下面创造了一个场景为文生图的 Prompt，并且给定了分别设置了正向和负向 Prompt，并且采用 `(())` 作为标识符。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = Prompt(\n",
    "    name=\"txt2img\",\n",
    "    template=\"txt2img template ((v1))\",\n",
    "    scene_type=PromptSceneType.Text2Image,\n",
    "    negative_template=\"negative template ((v3))\",\n",
    "    identifier=\"(())\",\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 上传/更新 Prompt"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于本地 Prompt，还可以使用 hub 将其上传保存至平台，方便后续快速使用，上传仅需要利用 `hub.push` 即可。关于 hub 的一些其他操作，可以参考 hub 的相关文档。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = Prompt(\n",
    "    template=\"本地 prompt {var1}\",\n",
    "    # 对于平台上的 prompt 来说，name 是必须的，因此上传前必须先设置\n",
    "    name=\"cookbook_prompt\"\n",
    ")\n",
    "\n",
    "# 也可以通过这种方式设置 name\n",
    "p.name = \"cookbook_prompt\"\n",
    "hub.push(p)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "后续还可以本地对 Prompt 进行更新，并继续用 `hub.push` 方法更新至平台上。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['new_var']\n",
      "('新的 Prompt hello', None)\n"
     ]
    }
   ],
   "source": [
    "p.set_template(\"新的 Prompt {new_var}\")\n",
    "hub.push(p)\n",
    "\n",
    "print(p.variables)\n",
    "print(p.render(new_var=\"hello\"))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 删除 Prompt"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "SDK 提供了 `delete` 方法，可以快速删除平台上的 Prompt。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = hub.load(\"prompt/cookbook_prompt\")\n",
    "p.delete()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果没有抛出异常，那么这条 Prompt 已经从平台上移除。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 保存/读取 Prompt"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通常在进行 Prompt 调优后，需要保存 Prompt 以便后续使用，SDK 也提供了 `save_to_file` 方法，可以将 Prompt 保存保存至本地。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = Prompt(template=\"这是一个用于{usage}的 Prompt\")\n",
    "p.save_to_file(\"test_prompt.tpl\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "而在再次使用时，只需要通过 `from_file` 方法即可读取 Prompt。\n",
    "\n",
    "如果希望调整 Prompt，可以直接对模版文件修改，从而既可以避免在代码中出现冗长的模版字符串，也可以因调整模版而反复修改代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "这是一个用于测试的 Prompt\n"
     ]
    }
   ],
   "source": [
    "p = Prompt.from_file(\"test_prompt.tpl\")\n",
    "prompt, _ = p.render(usage=\"测试\")\n",
    "print(prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "58f7cb64c3a06383b7f18d2a11305edccbad427293a2b4afa7abe8bfc810d4bb"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
